Use docopt's new syntax for repeatable options
authorFlorian Hahn <flo@fhahn.com>
Sat, 12 Sep 2015 21:32:35 +0000 (23:32 +0200)
committerFlorian Hahn <flo@fhahn.com>
Wed, 30 Sep 2015 19:30:53 +0000 (21:30 +0200)
src/bin/bench.rs
src/bin/build.rs
src/bin/doc.rs
src/bin/rustc.rs
src/bin/test.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/ops/cargo_test.rs
tests/support/mod.rs
tests/test_cargo_bench.rs
tests/test_cargo_compile.rs
tests/test_cargo_rustc.rs

index 47150dfab8948c641a6ecf663593e638d2d88157..7e658997d285a10b86ad9dcce1c2ad800f2b073f 100644 (file)
@@ -26,25 +26,25 @@ pub const USAGE: &'static str = "
 Execute all benchmarks of a local package
 
 Usage:
-    cargo bench [options] [-p SPEC --package SPEC]... [--] [<args>...]
+    cargo bench [options] [--] [<args>...]
 
 Options:
-    -h, --help               Print this message
-    --lib                    Benchmark only this package's library
-    --bin NAME               Benchmark only the specified binary
-    --example NAME           Benchmark only the specified example
-    --test NAME              Benchmark only the specified test target
-    --bench NAME             Benchmark only the specified bench target
-    --no-run                 Compile, but don't run benchmarks
-    -p SPEC, --package SPEC  Package to run benchmarks for
-    -j N, --jobs N           The number of jobs to run in parallel
-    --features FEATURES      Space-separated list of features to also build
-    --no-default-features    Do not build the `default` feature
-    --target TRIPLE          Build for the target triple
-    --manifest-path PATH     Path to the manifest to build benchmarks for
-    -v, --verbose            Use verbose output
-    -q, --quiet              No output printed to stdout
-    --color WHEN             Coloring: auto, always, never
+    -h, --help                   Print this message
+    --lib                        Benchmark only this package's library
+    --bin NAME                   Benchmark only the specified binary
+    --example NAME               Benchmark only the specified example
+    --test NAME                  Benchmark only the specified test target
+    --bench NAME                 Benchmark only the specified bench target
+    --no-run                     Compile, but don't run benchmarks
+    -p SPEC, --package SPEC ...  Package to run benchmarks for
+    -j N, --jobs N               The number of jobs to run in parallel
+    --features FEATURES          Space-separated list of features to also build
+    --no-default-features        Do not build the `default` feature
+    --target TRIPLE              Build for the target triple
+    --manifest-path PATH         Path to the manifest to build benchmarks for
+    -v, --verbose                Use verbose output
+    -q, --quiet                  No output printed to stdout
+    --color WHEN                 Coloring: auto, always, never
 
 All of the trailing arguments are passed to the benchmark binaries generated
 for filtering benchmarks and generally providing options configuring how they
index 6140ca961be10d675e9ec4ac4a2393f1c1cb973b..27bcf57b122e1c5443e26f0178e6adaf30c573d1 100644 (file)
@@ -28,25 +28,25 @@ pub const USAGE: &'static str = "
 Compile a local package and all of its dependencies
 
 Usage:
-    cargo build [options] [-p SPEC --package SPEC]...
+    cargo build [options]
 
 Options:
-    -h, --help               Print this message
-    -p SPEC, --package SPEC  Package to build
-    -j N, --jobs N           The number of jobs to run in parallel
-    --lib                    Build only this package's library
-    --bin NAME               Build only the specified binary
-    --example NAME           Build only the specified example
-    --test NAME              Build only the specified test target
-    --bench NAME             Build only the specified benchmark target
-    --release                Build artifacts in release mode, with optimizations
-    --features FEATURES      Space-separated list of features to also build
-    --no-default-features    Do not build the `default` feature
-    --target TRIPLE          Build for the target triple
-    --manifest-path PATH     Path to the manifest to compile
-    -v, --verbose            Use verbose output
-    -q, --quiet              No output printed to stdout
-    --color WHEN             Coloring: auto, always, never
+    -h, --help                   Print this message
+    -p SPEC, --package SPEC ...  Package to build
+    -j N, --jobs N               The number of jobs to run in parallel
+    --lib                        Build only this package's library
+    --bin NAME                   Build only the specified binary
+    --example NAME               Build only the specified example
+    --test NAME                  Build only the specified test target
+    --bench NAME                 Build only the specified benchmark target
+    --release                    Build artifacts in release mode, with optimizations
+    --features FEATURES          Space-separated list of features to also build
+    --no-default-features        Do not build the `default` feature
+    --target TRIPLE              Build for the target triple
+    --manifest-path PATH         Path to the manifest to compile
+    -v, --verbose                Use verbose output
+    -q, --quiet                  No output printed to stdout
+    --color WHEN                 Coloring: auto, always, never
 
 If the --package argument is given, then SPEC is a package id specification
 which indicates which package should be built. If it is not given, then the
index 8bc6289b5df380c0127aff099e2ce7d92ece9ed4..16fd12430ecdb5e2f710443bb84b485c90a8b3a9 100644 (file)
@@ -22,22 +22,22 @@ pub const USAGE: &'static str = "
 Build a package's documentation
 
 Usage:
-    cargo doc [options] [-p SPEC --package SPEC]...
+    cargo doc [options]
 
 Options:
-    -h, --help               Print this message
-    --open                   Opens the docs in a browser after the operation
-    -p SPEC, --package SPEC  Package to document
-    --no-deps                Don't build documentation for dependencies
-    -j N, --jobs N           The number of jobs to run in parallel
-    --release                Build artifacts in release mode, with optimizations
-    --features FEATURES      Space-separated list of features to also build
-    --no-default-features    Do not build the `default` feature
-    --target TRIPLE          Build for the target triple
-    --manifest-path PATH     Path to the manifest to document
-    -v, --verbose            Use verbose output
-    -q, --quiet              No output printed to stdout
-    --color WHEN             Coloring: auto, always, never
+    -h, --help                   Print this message
+    --open                       Opens the docs in a browser after the operation
+    -p SPEC, --package SPEC ...  Package to document
+    --no-deps                    Don't build documentation for dependencies
+    -j N, --jobs N               The number of jobs to run in parallel
+    --release                    Build artifacts in release mode, with optimizations
+    --features FEATURES          Space-separated list of features to also build
+    --no-default-features        Do not build the `default` feature
+    --target TRIPLE              Build for the target triple
+    --manifest-path PATH         Path to the manifest to document
+    -v, --verbose                Use verbose output
+    -q, --quiet                  No output printed to stdout
+    --color WHEN                 Coloring: auto, always, never
 
 By default the documentation for the local package and all dependencies is
 built. The output is all placed in `target/doc` in rustdoc's usual format.
index 4b7121f43e503eb5d65c66d1fc13385d4e4c25d7..f1fb15a479e56b01d5d76e8f2f4b6128ea68af26 100644 (file)
@@ -29,25 +29,25 @@ pub const USAGE: &'static str = "
 Compile a package and all of its dependencies
 
 Usage:
-    cargo rustc [options] [-p SPEC --package SPEC]... [--] [<opts>...]
+    cargo rustc [options] [--] [<opts>...]
 
 Options:
-    -h, --help               Print this message
-    -p SPEC, --package SPEC  The profile to compile for
-    -j N, --jobs N           The number of jobs to run in parallel
-    --lib                    Build only this package's library
-    --bin NAME               Build only the specified binary
-    --example NAME           Build only the specified example
-    --test NAME              Build only the specified test target
-    --bench NAME             Build only the specified benchmark target
-    --release                Build artifacts in release mode, with optimizations
-    --features FEATURES      Features to compile for the package
-    --no-default-features    Do not compile default features for the package
-    --target TRIPLE          Target triple which compiles will be for
-    --manifest-path PATH     Path to the manifest to fetch dependencies for
-    -v, --verbose            Use verbose output
-    -q, --quiet              No output printed to stdout
-    --color WHEN             Coloring: auto, always, never
+    -h, --help                   Print this message
+    -p SPEC, --package SPEC ...  The profile to compile for
+    -j N, --jobs N               The number of jobs to run in parallel
+    --lib                        Build only this package's library
+    --bin NAME                   Build only the specified binary
+    --example NAME               Build only the specified example
+    --test NAME                  Build only the specified test target
+    --bench NAME                 Build only the specified benchmark target
+    --release                    Build artifacts in release mode, with optimizations
+    --features FEATURES          Features to compile for the package
+    --no-default-features        Do not compile default features for the package
+    --target TRIPLE              Target triple which compiles will be for
+    --manifest-path PATH         Path to the manifest to fetch dependencies for
+    -v, --verbose                Use verbose output
+    -q, --quiet                  No output printed to stdout
+    --color WHEN                 Coloring: auto, always, never
 
 The specified target for the current package (or package specified by SPEC if
 provided) will be compiled along with all of its dependencies. The specified
index 9b89fb91211d73c33abe829d7496bf51611df664..09981e0bed8541bc8eba2cbb997d05cb87f43930 100644 (file)
@@ -28,27 +28,27 @@ pub const USAGE: &'static str = "
 Execute all unit and integration tests of a local package
 
 Usage:
-    cargo test [options] [-p SPEC --package SPEC]... [--] [<args>...]
+    cargo test [options] [--] [<args>...]
 
 Options:
-    -h, --help               Print this message
-    --lib                    Test only this package's library
-    --bin NAME               Test only the specified binary
-    --example NAME           Test only the specified example
-    --test NAME              Test only the specified integration test target
-    --bench NAME             Test only the specified benchmark target
-    --no-run                 Compile, but don't run tests
-    -p SPEC, --package SPEC  Package to run tests for
-    -j N, --jobs N           The number of jobs to run in parallel
-    --release                Build artifacts in release mode, with optimizations
-    --features FEATURES      Space-separated list of features to also build
-    --no-default-features    Do not build the `default` feature
-    --target TRIPLE          Build for the target triple
-    --manifest-path PATH     Path to the manifest to build tests for
-    -v, --verbose            Use verbose output
-    -q, --quiet              No output printed to stdout
-    --color WHEN             Coloring: auto, always, never
-    --no-fail-fast           Run all tests regardless of failure
+    -h, --help                   Print this message
+    --lib                        Test only this package's library
+    --bin NAME                   Test only the specified binary
+    --example NAME               Test only the specified example
+    --test NAME                  Test only the specified integration test target
+    --bench NAME                 Test only the specified benchmark target
+    --no-run                     Compile, but don't run tests
+    -p SPEC, --package SPEC ...  Package to run tests for
+    -j N, --jobs N               The number of jobs to run in parallel
+    --release                    Build artifacts in release mode, with optimizations
+    --features FEATURES          Space-separated list of features to also build
+    --no-default-features        Do not build the `default` feature
+    --target TRIPLE              Build for the target triple
+    --manifest-path PATH         Path to the manifest to build tests for
+    -v, --verbose                Use verbose output
+    -q, --quiet                  No output printed to stdout
+    --color WHEN                 Coloring: auto, always, never
+    --no-fail-fast               Run all tests regardless of failure
 
 All of the trailing arguments are passed to the test binaries generated for
 filtering tests and generally providing options configuring how they run. For
index 1c2ad0705aab39dae55751b5f70023e8b7db9c59..53167b0d4b78c22e291e3c638ff441633106604e 100644 (file)
@@ -54,6 +54,7 @@ pub struct TargetConfig {
 
 // Returns a mapping of the root package plus its immediate dependencies to
 // where the compiled libraries are all located.
+#[allow(deprecated)] // connect => join in 1.3
 pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package,
                                                            Vec<(&Target,
                                                                 &'a Profile)>)],
@@ -66,7 +67,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package,
                                      -> CargoResult<Compilation<'cfg>> {
 
     debug!("compile_targets: {}", pkg_targets.iter().map(|&(ref p, _)| p.name())
-                                                    .collect::<Vec<_>>().join(", "));
+                                                    .collect::<Vec<_>>().connect(", "));
 
     try!(links::validate(deps));
 
index 51357eca1f151e9e16abf099a612d71efd01b503..d1b985fa5c23cf3a1bcbdf9f3db10c6efd60ebf7 100644 (file)
@@ -62,7 +62,10 @@ fn compile_tests<'a>(manifest_path: &Path,
                      options: &TestOptions<'a>)
                      -> CargoResult<Compilation<'a>> {
     let mut compilation = try!(ops::compile(manifest_path, &options.compile_opts));
-    compilation.tests.sort();
+    compilation.tests.iter_mut()
+                     .map(|&mut (_, ref mut tests)|
+                          tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2)))
+                     .collect::<Vec<_>>();
     Ok(compilation)
 }
 
@@ -76,24 +79,26 @@ fn run_unit_tests(options: &TestOptions,
 
     let mut errors = Vec::new();
 
-    for &(_, ref exe) in &compilation.tests {
-        let to_display = match util::without_prefix(exe, &cwd) {
-            Some(path) => path,
-            None => &**exe,
-        };
-        let mut cmd = try!(compilation.target_process(exe, &compilation.package));
-        cmd.args(test_args);
-        try!(config.shell().concise(|shell| {
-            shell.status("Running", to_display.display().to_string())
-        }));
-        try!(config.shell().verbose(|shell| {
-            shell.status("Running", cmd.to_string())
-        }));
+    for &(ref pkg, ref tests) in &compilation.tests {
+        for &(_, ref exe) in tests {
+            let to_display = match util::without_prefix(exe, &cwd) {
+                Some(path) => path,
+                None => &**exe,
+            };
+            let mut cmd = try!(compilation.target_process(exe, pkg));
+            cmd.args(test_args);
+            try!(config.shell().concise(|shell| {
+                shell.status("Running", to_display.display().to_string())
+            }));
+            try!(config.shell().verbose(|shell| {
+                shell.status("Running", cmd.to_string())
+            }));
 
-        if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) {
-            errors.push(e);
-            if !options.no_fail_fast {
-                break
+            if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) {
+                errors.push(e);
+                if !options.no_fail_fast {
+                    break
+                }
             }
         }
     }
@@ -107,15 +112,20 @@ fn run_doc_tests(options: &TestOptions,
                  -> CargoResult<Vec<ProcessError>> {
     let mut errors = Vec::new();
     let config = options.compile_opts.config;
-    let libs = compilation.package.targets().iter()
-                    .filter(|t| t.doctested())
-                    .map(|t| (t.src_path(), t.name(), t.crate_name()));
-    for (lib, name, crate_name) in libs {
+
+    let mut libs = vec![];
+    for package in compilation.to_doc_test.iter() {
+        libs.extend(package.targets().iter()
+                      .filter(|t| t.doctested())
+                      .map(|t| (package, t.src_path(), t.name(), t.crate_name())));
+    }
+
+    for (package, lib, name, crate_name) in libs {
         try!(config.shell().status("Doc-tests", name));
-        let mut p = try!(compilation.rustdoc_process(&compilation.package));
+        let mut p = try!(compilation.rustdoc_process(package));
         p.arg("--test").arg(lib)
          .arg("--crate-name").arg(&crate_name)
-         .cwd(compilation.package.root());
+         .cwd(package.root());
 
         for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
             let mut arg = OsString::from("dependency=");
@@ -169,44 +179,3 @@ fn run_doc_tests(options: &TestOptions,
     }
     Ok(errors)
 }
-
-fn build_and_run<'a>(manifest_path: &Path,
-                     options: &TestOptions<'a>,
-                     test_args: &[String])
-                     -> CargoResult<Result<Compilation<'a>, ProcessError>> {
-    let config = options.compile_opts.config;
-    let mut source = try!(PathSource::for_path(&manifest_path.parent().unwrap(),
-                                               config));
-    try!(source.update());
-
-    let mut compile = try!(ops::compile(manifest_path, &options.compile_opts));
-    if options.no_run { return Ok(Ok(compile)) }
-    compile.tests.iter_mut()
-                 .map(|&mut (_, ref mut tests)|
-                      tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2)))
-                 .collect::<Vec<_>>();
-
-    let cwd = config.cwd();
-    for &(ref pkg, ref tests) in &compile.tests {
-        for &(_, ref exe) in tests {
-            let to_display = match util::without_prefix(exe, &cwd) {
-                Some(path) => path,
-                None => &**exe,
-            };
-            let mut cmd = try!(compile.target_process(exe, pkg));
-            cmd.args(test_args);
-            try!(config.shell().concise(|shell| {
-                shell.status("Running", to_display.display().to_string())
-            }));
-            try!(config.shell().verbose(|shell| {
-                shell.status("Running", cmd.to_string())
-            }));
-            match ExecEngine::exec(&mut ProcessEngine, cmd) {
-                Ok(()) => {}
-                Err(e) => return Ok(Err(e))
-            }
-        }
-    }
-
-    Ok(Ok(compile))
-}
index 0f7602e99daa1b2692420253b061d627b0179751..4411dd62582c32a3a8593f2631633dd6ee35f2c5 100644 (file)
@@ -269,7 +269,8 @@ pub struct Execs {
     expect_stdout: Option<String>,
     expect_stdin: Option<String>,
     expect_stderr: Option<String>,
-    expect_exit_code: Option<i32>
+    expect_exit_code: Option<i32>,
+    expect_stdout_contains: Vec<String>
 }
 
 impl Execs {
@@ -289,6 +290,11 @@ impl Execs {
         self
     }
 
+    pub fn with_stdout_contains<S: ToString>(mut self, expected: S) -> Execs {
+        self.expect_stdout_contains.push(expected.to_string());
+        self
+    }
+
     fn match_output(&self, actual: &Output) -> ham::MatchResult {
         self.match_status(actual)
             .and(self.match_stdout(actual))
@@ -312,6 +318,8 @@ impl Execs {
     fn match_stdout(&self, actual: &Output) -> ham::MatchResult {
         self.match_std(self.expect_stdout.as_ref(), &actual.stdout,
                        "stdout", &actual.stderr)
+            .and(self.match_contains(self.expect_stdout_contains.as_ref(),
+                 &actual.stdout, "stdout"))
     }
 
     fn match_stderr(&self, actual: &Output) -> ham::MatchResult {
@@ -319,6 +327,40 @@ impl Execs {
                        "stderr", &actual.stdout)
     }
 
+    #[allow(deprecated)] // connect => join in 1.3
+    fn match_contains(&self, expect: &[String], actual: &[u8],
+                      description: &str) -> ham::MatchResult {
+        for s in expect {
+            let a: Vec<&str> = match str::from_utf8(actual) {
+                Err(..) => return Err(format!("{} was not utf8 encoded",
+                                           description)),
+                Ok(actual) => actual.lines().collect(),
+            };
+            let e: Vec<&str> = s.lines().collect();
+
+            let first = e.first().unwrap();
+            let mut ai = a.iter();
+            match ai.position(|s| lines_match(first, s)) {
+                Some(_) => {
+                    let match_count = ai.zip(e.iter().skip(1))
+                                        .take_while(|&(a, e)| lines_match(a, e)).count();
+                    if match_count != (e.len() - 1) {
+                        return ham::expect(false,
+                                           format!("expected: {}\n\
+                                                    actual: {}",
+                                                    e.connect("\n"),
+                                                    a.iter().take(e.len()).map(|&s| s)
+                                                     .collect::<Vec<_>>().connect("\n")));
+                    }
+                },
+                None => {
+                    return ham::expect(false, format!("no match"));
+                }
+            };
+        }
+        ham::expect(true, format!("OK"))
+    }
+
     #[allow(deprecated)] // connect => join in 1.3
     fn match_std(&self, expected: Option<&String>, actual: &[u8],
                  description: &str, extra: &[u8]) -> ham::MatchResult {
@@ -446,7 +488,8 @@ pub fn execs() -> Execs {
         expect_stdout: None,
         expect_stderr: None,
         expect_stdin: None,
-        expect_exit_code: None
+        expect_exit_code: None,
+        expect_stdout_contains: vec![]
     }
 }
 
index 5e3b21cad53301a972a7a7488e61c5d481c5aa3f..1439172586d03869d72d20f7662263ea7fc3611d 100644 (file)
@@ -922,3 +922,88 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
 
 ", compiling = COMPILING, running = RUNNING)));
 });
+
+test!(test_bench_multiple_packages {
+    if !::is_nightly() { return }
+
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "foo"
+            authors = []
+            version = "0.1.0"
+
+            [dependencies.bar]
+            path = "../bar"
+
+            [dependencies.baz]
+            path = "../baz"
+        "#)
+        .file("src/lib.rs", "");
+
+    let bar = project("bar")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "bar"
+            authors = []
+            version = "0.1.0"
+
+            [[bench]]
+            name = "bbar"
+            test = true
+        "#)
+        .file("src/lib.rs", "")
+        .file("benches/bbar.rs", r#"
+            #![feature(test)]
+            extern crate test;
+
+            use test::Bencher;
+
+            #[bench]
+            fn bench_bar(_b: &mut Bencher) {}
+        "#);
+    bar.build();
+
+    let baz = project("baz")
+        .file("Cargo.toml", r#"
+            [project]
+            name = "baz"
+            authors = []
+            version = "0.1.0"
+
+            [[bench]]
+            name = "bbaz"
+            test = true
+        "#)
+        .file("src/lib.rs", "")
+        .file("benches/bbaz.rs", r#"
+            #![feature(test)]
+            extern crate test;
+
+            use test::Bencher;
+
+            #[bench]
+            fn bench_baz(_b: &mut Bencher) {}
+        "#);
+    baz.build();
+
+
+    assert_that(p.cargo_process("bench").arg("-p").arg("bar").arg("-p").arg("baz"),
+                execs().with_status(0)
+                       .with_stdout_contains(&format!("\
+{running} target[..]release[..]bbaz-[..]
+
+running 1 test
+test bench_baz ... bench:           0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+", running = RUNNING))
+                       .with_stdout_contains(&format!("\
+{running} target[..]release[..]bbar-[..]
+
+running 1 test
+test bench_bar ... bench:           0 ns/iter (+/- 0)
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
+", running = RUNNING)));
+});
index 87e47c2d44686d50bacd49304772fbf2753fbc40..c67e50bb0addee3d21c90b9717f28d7a5269c658 100644 (file)
@@ -1927,8 +1927,6 @@ test!(rustc_no_trans {
 });
 
 test!(build_multiple_packages {
-
-
     let p = project("foo")
         .file("Cargo.toml", r#"
             [package]
@@ -1969,7 +1967,9 @@ test!(build_multiple_packages {
         .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }");
     p.build();
 
-    assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2").arg("-p").arg("foo"), execs());
+    assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2")
+                                        .arg("-p").arg("foo"),
+                execs());
 
     assert_that(&p.bin("foo"), existing_file());
     assert_that(process(&p.bin("foo")).unwrap(),
index 8000517932c168dfceec628ea1259b2d7fa2dae5..18a09fae133ccea8cadde4bd668481478ed8a5cd 100644 (file)
@@ -1,7 +1,9 @@
 use std::path::MAIN_SEPARATOR as SEP;
 use support::{execs, project};
 use support::{COMPILING, RUNNING};
-use hamcrest::{assert_that};
+use hamcrest::{assert_that, existing_file};
+use cargo::util::process;
+
 
 fn setup() {
 }
@@ -296,3 +298,68 @@ test!(build_only_bar_dependency {
                 compiling = COMPILING, running = RUNNING,
                 url = foo.url())));
 });
+
+test!(build_multiple_dependencies {
+    let foo = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.0.1"
+            authors = []
+
+            [dependencies.bar]
+                path = "../bar"
+
+            [dependencies.baz]
+                path = "../baz"
+        "#)
+        .file("src/main.rs", r#"
+            fn main() {}
+        "#);
+    foo.build();
+    let bar = project("bar")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "bar"
+            version = "0.1.0"
+            authors = []
+        "#)
+        .file("src/main.rs", r#"
+            fn main() {
+                if cfg!(flag = "1") { println!("Yeah from bar!"); }
+            }
+        "#);
+
+    bar.build();
+    let baz = project("baz")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "baz"
+            version = "0.1.0"
+            authors = []
+        "#)
+        .file("src/main.rs", r#"
+            fn main() {
+                if cfg!(flag = "1") { println!("Yeah from baz!"); }
+            }
+        "#);
+    baz.build();
+
+    assert_that(foo.cargo_process("rustc").arg("-v").arg("-p").arg("bar")
+                .arg("-p").arg("baz").arg("--").arg("--cfg").arg("flag=\"1\""),
+                execs()
+                .with_status(0));
+
+    let bar_bin = &foo.build_dir().join("debug").join("deps").join("bar");
+    assert_that(bar_bin, existing_file());
+
+    assert_that(
+      process(bar_bin).unwrap(),
+      execs().with_stdout("Yeah from bar!\n"));
+
+    let baz_bin = &foo.build_dir().join("debug").join("deps").join("baz");
+    assert_that(bar_bin, existing_file());
+    assert_that(
+      process(baz_bin).unwrap(),
+      execs().with_stdout("Yeah from baz!\n"));
+});